home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / packagetool / sample package / htmlsample sources / renderingwindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  31.5 KB  |  956 lines

  1. /*
  2.     File: RenderingWindow.c
  3.     
  4.     Description:
  5.         This file contains the routines used to manage the windows displayed
  6.     by the HTMLSample application.
  7.     
  8.     HTMLSample is an application illustrating how to use the new
  9.     HTMLRenderingLib services found in Mac OS 9. HTMLRenderingLib
  10.     is Apple's light-weight HTML rendering engine capable of
  11.     displaying HTML files.
  12.  
  13.     Copyright:
  14.         © Copyright 1999 Apple Computer, Inc. All rights reserved.
  15.     
  16.     Disclaimer:
  17.         IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  18.         ("Apple") in consideration of your agreement to the following terms, and your
  19.         use, installation, modification or redistribution of this Apple software
  20.         constitutes acceptance of these terms.  If you do not agree with these terms,
  21.         please do not use, install, modify or redistribute this Apple software.
  22.  
  23.         In consideration of your agreement to abide by the following terms, and subject
  24.         to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  25.         copyrights in this original Apple software (the "Apple Software"), to use,
  26.         reproduce, modify and redistribute the Apple Software, with or without
  27.         modifications, in source and/or binary forms; provided that if you redistribute
  28.         the Apple Software in its entirety and without modifications, you must retain
  29.         this notice and the following text and disclaimers in all such redistributions of
  30.         the Apple Software.  Neither the name, trademarks, service marks or logos of
  31.         Apple Computer, Inc. may be used to endorse or promote products derived from the
  32.         Apple Software without specific prior written permission from Apple.  Except as
  33.         expressly stated in this notice, no other rights or licenses, express or implied,
  34.         are granted by Apple herein, including but not limited to any patent rights that
  35.         may be infringed by your derivative works or by other works in which the Apple
  36.         Software may be incorporated.
  37.  
  38.         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  39.         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  40.         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  41.         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  42.         COMBINATION WITH YOUR PRODUCTS.
  43.  
  44.         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  45.         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  46.         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  47.         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  48.         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  49.         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  50.         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  51.  
  52.     Change History (most recent first):
  53.         Wed, Dec 22, 1999 -- created
  54. */
  55.  
  56.  
  57. #include "RenderingWindow.h"
  58.  
  59. #include <HTMLRendering.h>
  60. #include <Resources.h>
  61. #include <StdDef.h>
  62. #include <string.h>
  63. #include <Sound.h>
  64.  
  65. #include "History.h"
  66. #include "CIconButtons.h"
  67. #include "SampleUtils.h"
  68. #include "HTMLSample.h"
  69.  
  70.  
  71.     /* resource id numbers for PICT resources used
  72.     for drawing the fill area to the right of the buttons */
  73. enum {
  74.     kLeftBarPicture = 128,
  75.     kCenterBarPicture = 129,
  76.     kRightBarPicture = 130
  77. };
  78.  
  79.     /* ASCII codes for the arrow keys on the keyboard */
  80. enum {
  81.     kLeftArrowKey = 28,
  82.     kUpArrowKey = 30,
  83.     kDownArrowKey = 29
  84. };
  85.  
  86.     /* color icon button resources for the default
  87.     navigation buttons. */
  88. enum {
  89.     kBackDefaultButton = 128,
  90.     kHomeDefaultButton = 129,
  91.     kForwardDefaultButton = 130
  92. };
  93.  
  94.     /* constants used for adding custom buttons. */
  95. enum {
  96.     kExtraButtonsMax = 4,
  97.     kExtraButtonsListID = 128
  98. };
  99.  
  100.     /* the resource id for the main window's
  101.     WIND resource. */
  102. enum {
  103.     kRenderingWindowID = 128
  104. };
  105.  
  106.  
  107.  
  108.  
  109. /* RWindowHandle's refer to a data structure created
  110.     for each rendering window to store various state
  111.     variables used for maintaining the window on the
  112.     screen.  Most importantly, for this example, this
  113.     is where a reference to the HTML rendering object
  114.     is stored.  A handle to this structure is stored in
  115.     the rendering window's refcon field. */
  116.     
  117. typedef struct RWindowStruct RWindowVars;
  118. typedef RWindowVars **RWindowHandle;
  119.  
  120. struct RWindowStruct {
  121.     RWindowHandle prev, next; /* list of open rendering windows */
  122.     WindowPtr rwindow;    /* a pointer to the window */
  123.     HRReference renderer;    /* a reference to the rendering object */
  124.     HistoryDataHandle history;    /* history of visited links for this window */
  125.     Boolean isActive;    /* true when this window is the frontmost window. */
  126.     CIconButtonHandle bback, bhome, bforward;    /* the default buttons */
  127.     short nExtraButtons; /* the number of extra buttons */
  128.     CIconButtonHandle extraButtons[1]; /* handles to the extra buttons */
  129. };
  130.  
  131.  
  132.     /* these picture handles are used for drawing the fill area
  133.     to the right of the buttons in the top of the window.  The
  134.     resources these variables reference are read in when
  135.     InitRenderingWindows is called. */
  136. PicHandle gFBLeft = NULL, gFBCenter = NULL, gFBRight = NULL;
  137.  
  138.  
  139.     /* a list of open rendering windows. */
  140. RWindowHandle gRWFirst = NULL, gRWLast = NULL;
  141.  
  142.  
  143.     /* the global history is used to store 'all' visited links for
  144.     every window.  */
  145. HistoryDataHandle gGlobalHistory = NULL;
  146.  
  147.  
  148.     /* gRenderingWindowsOpen is set to true when InitRenderingWindows
  149.         is successful. */
  150. Boolean gRenderingWindowsOpen = false;
  151.  
  152.  
  153. /* InitRenderingWindows is called to initialize the environment used by 
  154.     routines defined in this file.  It should be called before any of the 
  155.     other routines defined in this file are called. */
  156. OSStatus InitRenderingWindows(void) {
  157.         /* get the pictures for drawing the fill
  158.         area to the right of the buttons from the
  159.         resource file */
  160.     gFBLeft = GetPicture(kLeftBarPicture);
  161.     if (gFBLeft == NULL) return resNotFound;
  162.     gFBCenter = GetPicture(kCenterBarPicture);
  163.     if (gFBCenter == NULL) return resNotFound;
  164.     gFBRight = GetPicture(kRightBarPicture);
  165.     if (gFBRight == NULL) return resNotFound;
  166.         /* initialize the list of opened windows */
  167.     gRWFirst = gRWLast = NULL;
  168.         /* allocate the global history */
  169.     gGlobalHistory = NewHistory();
  170.     if (gGlobalHistory == NULL) return memFullErr;
  171.         /* set the open flag */
  172.     gRenderingWindowsOpen = true;
  173.         /* done */
  174.     return noErr;
  175. }
  176.  
  177.  
  178. /* CloseRenderingWindows closes any open rendering windows and
  179.     deallocates any structures allocated when InitRenderingWindows
  180.     was called. */
  181. OSStatus CloseRenderingWindows(void) {
  182.     if (gRenderingWindowsOpen) {
  183.             /* close any open rendering windows */
  184.         while (gRWFirst != NULL)
  185.             RWCloseWindow((**gRWFirst).rwindow);
  186.             /* release the global history */
  187.         DisposeHistory(gGlobalHistory);
  188.             /* reset the open flag */
  189.         gRenderingWindowsOpen = false;
  190.     }
  191.     return noErr;
  192. }
  193.  
  194.  
  195.  
  196. /* MyHRURLToFSSpecProc is the URL to FSSpec mapping defined for rendering windows.
  197.     it calls the HTMLRenderingLib HRUtilGetFSSpecFromURL routine to map the url
  198.     to a FSSpec and then it checks to see if the file exists and if it's an application.
  199.     If the file does not exist, it re-directs the URL to refer to the error page.  If the
  200.     file exists and it's an application, it launches the application. */
  201. static OSStatus MyHRURLToFSSpecProc(const char *rootURL, const char *linkURL,
  202.             FSSpec *fsspec, URLSourceType urlSourceType, void *refCon) {
  203.     RWindowHandle rwv;
  204.     FSSpec spec;
  205.     OSStatus err;
  206.     FInfo fndrInfo;
  207.         /* set up locals */
  208.     rwv = (RWindowHandle) refCon;
  209.         /* as the rendering library to map the file
  210.         for us. */
  211.     err = HRUtilGetFSSpecFromURL(rootURL, linkURL, &spec);
  212.     if (err != noErr) goto bail;
  213.         /* check to see if the file exists. */
  214.     err = FSpGetFInfo(&spec, &fndrInfo);
  215.     if (err != noErr) goto bail;
  216.         /* if the file is an application, launch it */
  217.     if (fndrInfo.fdType == 'APPL') {
  218.         LaunchParamBlockRec launchpb;
  219.         memset(&launchpb, 0, sizeof(launchpb));
  220.         launchpb.launchBlockID = extendedBlock;
  221.         launchpb.launchEPBLength = extendedBlockLen;
  222.         launchpb.launchFileFlags = launchNoFileFlags;
  223.         launchpb.launchControlFlags = launchContinue;
  224.         launchpb.launchAppSpec = &spec;
  225.         err = LaunchApplication(&launchpb);
  226.             /* we return an error so the HTMLRenderingLib
  227.             does not try to draw the file. */
  228.         return fnfErr;
  229.     }
  230.         /* return the FSSpec */
  231.     *fsspec = spec;
  232.     return noErr;
  233. bail:
  234.         /* if an error occured and we're looking for a
  235.         HTML source file, then we re-direct the URL to the
  236.         error file. */
  237.     if (urlSourceType == kHRLookingForHTMLSource) {
  238.         Handle rootURL, errorLink;
  239.             /* the link we have in our resources is application
  240.             relative, so we need to get the application's URL first. */
  241.         if (GetApplicationFolderURL(&rootURL) == noErr) {
  242.                 /* and then we pull the application relative link
  243.                 from the resource file. */
  244.             errorLink = GetResource(kCStyleStringResourceType, kErrorPageURLString);
  245.             if (errorLink != NULL) {
  246.                 HLock(errorLink);
  247.                 HLock(rootURL);
  248.                     /* after retrieving the URL and the link, we ask the
  249.                     rendering library to map them to a FSSpec. */
  250.                 if (HRUtilGetFSSpecFromURL(*rootURL, *errorLink, &spec) == noErr) {
  251.                         /* then, if the file exists, we return a FSSpec referring
  252.                         to the error file. */
  253.                     if (FSpGetFInfo(&spec, &fndrInfo) == noErr) {
  254.                         *fsspec = spec;
  255.                         err = noErr;
  256.                     }
  257.                 }
  258.                 HUnlock(errorLink);
  259.             }
  260.             DisposeHandle(rootURL);
  261.         }
  262.     }
  263.     return err;
  264. }
  265.  
  266.  
  267. /* RedrawWindowButtons redraws the three default buttons in the top
  268.     of the window.  the way they are drawn depends on what commands
  269.     are available at the time when this routine is called. here we set the
  270.     origin to 0,0, and the clip region  to the window's clip region.  We
  271.     do so because when this routine is called the origin and clip region 
  272.     may have been left in an unknown state by the rendering library.*/
  273. static void RedrawWindowButtons(RWindowHandle rwv) {
  274.     RgnHandle clipsave;
  275.         /* set the current grafport to the window's */
  276.     SetPort((**rwv).rwindow);
  277.         /* set the origin before drawing.  it may be incorrect when we're called. */
  278.     SetOrigin(0, 0); 
  279.         /* save the clipping region going to links with anchors sets it incorrectly */
  280.     clipsave = NewRgn(); 
  281.     GetClip(clipsave);
  282.     ClipRect(&(**rwv).rwindow->portRect);
  283.         /* draw the buttons */
  284.     DrawCIconButton((**rwv).bback, (CanGoBack((**rwv).history) ? kCBup : kCBdisabled));
  285.     DrawCIconButton((**rwv).bhome, (CanGoHome((**rwv).history) ? kCBup : kCBdisabled));
  286.     DrawCIconButton((**rwv).bforward, (CanGoForward((**rwv).history) ? kCBup : kCBdisabled));
  287.         /* restore the clipping region */
  288.     SetClip(clipsave);
  289.     DisposeRgn(clipsave);
  290. }
  291.  
  292.  
  293. /* MyNewURLProc is called by the rendering library whenever a new HTML file
  294.     is brought into the display.  This routine will be called with the HTML file's
  295.     URL. if addToHistory is true, then the file is added to the history of visited
  296.     links.  */
  297. static OSStatus MyNewURLProc( const char *url, const char *targetFrame,
  298.         Boolean addToHistory, void *refCon, HRNewURLUPP userUPP) {
  299.     RWindowHandle rwv;
  300.     Str255 title;
  301.     Point theSize;
  302.         /* set up locals */
  303.     rwv = (RWindowHandle) refCon;
  304.         /* set up the drawing environment */
  305.     SetPort((**rwv).rwindow);
  306.     SetOrigin(0, 0);
  307.         /* set the window's title to the new file */
  308.     if (HRGetTitle( (**rwv).renderer, title) == noErr)
  309.         SetWTitle((**rwv).rwindow, title);
  310.     else title[0] = 0;
  311.         /* set the window's standard state rectangle to
  312.         the 'best' size for displaying this page. If the user
  313.         zooms the window, it will go to this size.  */
  314.     if (HRGetRenderedImageSize((**rwv).renderer, &theSize) == noErr)
  315.         SetWindowStandardStateSize((**rwv).rwindow, theSize.h + 16, theSize.v + 32 + 16);
  316.         /* if add to history is true, then we add the URL to both
  317.         the window's history and to the global history. */
  318.     if (addToHistory) {
  319.             /* add to the window's history */
  320.         AddToHistory((**rwv).history, url, title);
  321.             /* add tot the global history. */
  322.         AddToHistory(gGlobalHistory, url, "\p");
  323.             /* redraw the window's controls.  We do
  324.             this here because their visual state depends
  325.             on the state of the window's history. */
  326.         RedrawWindowButtons(rwv);
  327.     }
  328.         /* done */
  329.     return noErr;
  330. }
  331.  
  332.  
  333. /* MyHRWasURLVisitedProc is called by the HTML rendering library
  334.     when it would like to determine if a link has been visited.  This
  335.     information is used when drawing links. */
  336. static Boolean MyHRWasURLVisitedProc(const char *url, void *refCon) {
  337.         /* here we return true if the link can be found in the
  338.         global history of all visited links, not just the window's history. */
  339.     return InHistory(gGlobalHistory, url);
  340. }
  341.  
  342.  
  343. /* URLContainsAnchor returns true if a URL contains
  344.     an anchor.  i.e. it contains a # character. */
  345. static Boolean URLContainsAnchor(char const *url) {
  346.     char const *cp;
  347.     for (cp = url; *cp != '\0'; cp++)
  348.         if (*cp == '#')
  349.             return true;
  350.     return false;
  351. }
  352.  
  353.  
  354. /* RWGotoURL displays HTML file referred to by the url in the
  355.     rendering window.  if addToHistory is true, then the window
  356.     will be added to the window's history list. */
  357. OSStatus RWGotoURL(WindowPtr rWin, char* url, Boolean addToHistory) {
  358.     RWindowHandle rwv;
  359.     OSStatus err;
  360.     Point origin = {0, 0};
  361.     Rect donedrawingbox;
  362.         /* set up locals */
  363.     rwv = (RWindowHandle) GetWRefCon(rWin);
  364.  
  365.         /* if the URL does not contain an anchor, then scroll
  366.         the HTML view to the origin. */
  367.     if ( ! URLContainsAnchor(url)) {
  368.         err = HRScrollToLocation((**rwv).renderer, &origin);
  369.         if (err != noErr) goto bail;
  370.     }
  371.         /* ask the rendering object to display the HTML page
  372.         referred to by the URL.  note, we pass the addToHistory to
  373.         this routine which in turn passes it to our MyNewURLProc
  374.         routine. */
  375.     err = HRGoToURL((**rwv).renderer, url, addToHistory, false);
  376.     if (err != noErr) goto bail;
  377.     
  378.         /* draw the new page */
  379.     err = HRDraw((**rwv).renderer, NULL);
  380.     if (err != noErr) goto bail;
  381.     
  382.         /* if addToHistory is false, then we would not
  383.         have re-drawn the buttons inside of our MyNewURLProc
  384.         routine so we should draw them here. */
  385.     if ( ! addToHistory)
  386.         RedrawWindowButtons(rwv);
  387.         
  388.         /* we validate the areas that were drawn by this
  389.         routine.  This is to avoid unnecessary redraws when
  390.         the window is first opened.  When the window is opened,
  391.         an update event will be posted for its entire contents.
  392.         These calls prevent the areas we have just drawn from
  393.         being re-drawn when the update event is processed. */
  394.     SetRect(&donedrawingbox, 0, 0, 32*3, 32);
  395.     ValidRect(&donedrawingbox);
  396.     donedrawingbox = rWin->portRect;
  397.     donedrawingbox.top += 33;
  398.     ValidRect(&donedrawingbox);
  399.  
  400.         /* done */
  401.     return noErr;
  402. bail:
  403.     return err;
  404. }
  405.  
  406. void debugf(char const *fmt, ...);
  407.  
  408. /* RWGotoAppRelLink displays HTML file referred to by the application
  409.     relative link in the rendering window.  if addToHistory is true, then
  410.     the window will be added to the window's history list. */
  411. OSStatus RWGotoAppRelLink(WindowPtr rWin, char* linkstr, Boolean addToHistory) {
  412.  
  413.     OSStatus err;
  414.     Handle rootURL, fullURL;
  415.         /* set up our locals */
  416.     rootURL = fullURL = NULL;
  417.         /* get the URL for the application's folder */
  418.     err = GetApplicationFolderURL(&rootURL);
  419.     if (err != noErr) goto bail;
  420.         /* allocate a handle for storing the full URL */
  421.     fullURL = NewHandle(0);
  422.     if (fullURL == NULL) { err = memFullErr; goto bail; }
  423.         /* ask the HTML rendering library to combine
  424.         the url and the link to make a complete URL */
  425.     HLock(rootURL);
  426.     err = HRUtilCreateFullURL(*rootURL, linkstr, fullURL);
  427.     if (err != noErr) goto bail;
  428.     HUnlock(rootURL);
  429.         /* call the RWGotoURL to bring the HTML file into view. */
  430.     MoveHHi(fullURL);
  431.     HLock(fullURL);
  432.     err = RWGotoURL(rWin, *fullURL, addToHistory);
  433.     if (err != noErr) goto bail;
  434.         /* clean up our locals */
  435.     DisposeHandle(rootURL);
  436.     DisposeHandle(fullURL);
  437.         /* done */
  438.     return noErr;
  439. bail:
  440.         /* on error, clean up and return the error. */
  441.     if (rootURL != NULL) DisposeHandle(rootURL);
  442.     if (fullURL != NULL) DisposeHandle(fullURL);
  443.     return err;
  444. }
  445.  
  446.  
  447. /* GoBackCommand is called whenever the user chooses
  448.     'go back' by either picking the menu item, clicking on
  449.     the button, or using the left arrow key on the keyboard. */
  450. static void GoBackCommand(RWindowHandle rwv) {
  451.     char** theURL;
  452.         /* get previous the URL from the window's history. */
  453.     if (GoBack((**rwv).history, (Handle*) &theURL) == noErr) {
  454.         MoveHHi((Handle) theURL);
  455.         HLock((Handle) theURL);
  456.             /* call the RWGotoURL routine to bring the
  457.             HTML file referred to by the URL into view. */
  458.         RWGotoURL((**rwv).rwindow, *theURL, false);
  459.  
  460.         DisposeHandle((Handle) theURL);
  461.     }
  462. }
  463.  
  464. /* GoHomeCommand is called whenever the user chooses
  465.     'go home' by either picking the menu item, clicking on
  466.     the button, or using the left arrow key on the keyboard. 
  467.     The file opened by this command will be the first file
  468.     displayed in the window when it was opened. */
  469. static void GoHomeCommand(RWindowHandle rwv) {
  470.     char** theURL;
  471.         /* get first the URL from the window's history. */
  472.     if (GoHome((**rwv).history, (Handle*) &theURL) == noErr) {
  473.         MoveHHi((Handle) theURL);
  474.         HLock((Handle) theURL);
  475.             /* call the RWGotoURL routine to bring the
  476.             HTML file referred to by the URL into view. */
  477.         RWGotoURL((**rwv).rwindow, *theURL, false);
  478.  
  479.         DisposeHandle((Handle) theURL);
  480.     }
  481. }
  482.  
  483.  
  484. /* GoForwardCommand is called whenever the user chooses
  485.     'go forward' by either picking the menu item, clicking on
  486.     the button, or using the left arrow key on the keyboard. */
  487. static void GoForwardCommand(RWindowHandle rwv) {
  488.     char** theURL;
  489.         /* get next the URL from the window's history. */
  490.     if (GoForward((**rwv).history, (Handle*) &theURL) == noErr) {
  491.         MoveHHi((Handle) theURL);
  492.         HLock((Handle) theURL);
  493.             /* call the RWGotoURL routine to bring the
  494.             HTML file referred to by the URL into view. */
  495.         RWGotoURL((**rwv).rwindow, *theURL, false);
  496.  
  497.         DisposeHandle((Handle) theURL);
  498.     }
  499. }
  500.  
  501.  
  502. /* RWGoToButtonPage is called whenever the user clicks on
  503.     a custom button.  This routine attempts to load the
  504.     application relative URL stored in the button's string
  505.     data. */
  506. static OSStatus RWGoToButtonPage(WindowPtr rWin, CIconButtonHandle theButton) {
  507.     RWindowHandle rwv;
  508.     OSStatus err;
  509.     Handle linkURL;
  510.         /* set up locals */
  511.     linkURL = NULL;
  512.     rwv = (RWindowHandle) GetWRefCon(rWin);    
  513.         /* get the application relative link from the button */
  514.     err = GetCIconButtonStringData(theButton, &linkURL);
  515.     if (err != noErr) goto bail;
  516.         /* call RWGotoAppRelLink to bring the HTML file
  517.         referred to by the link into the display. */
  518.     MoveHHi(linkURL);
  519.     HLock(linkURL);
  520.     err = RWGotoAppRelLink(rWin, *linkURL, true);
  521.     if (err != noErr) goto bail;
  522.         /* clean up */
  523.     DisposeHandle(linkURL);
  524.         /* done */
  525.     return noErr;
  526. bail:
  527.     if (linkURL != NULL) DisposeHandle(linkURL);
  528.     return err;
  529. }
  530.  
  531.  
  532.  
  533. /* DrawFillBar draws the fill area to the right of the
  534.     button controls in the top of the window. */
  535. static OSStatus DrawFillBar(Rect *bounds) {
  536.     Rect r;
  537.         /* Draw the left side */
  538.     r = *bounds;
  539.     r.right = r.left + 8;
  540.     DrawPicture(gFBLeft, &r);
  541.         /* draw the center */
  542.     r = *bounds;
  543.     r.left += 8;
  544.     r.right -= 8;
  545.     DrawPicture(gFBCenter, &r);
  546.         /* draw the right side */
  547.     r = *bounds;
  548.     r.left = r.right - 8;
  549.     DrawPicture(gFBRight, &r);
  550.         /* done */
  551.     return noErr;
  552. }
  553.  
  554.  
  555.  
  556. /* RWUpdate should be called in response to an update event.
  557.     it calls BeginUpdate and EndUpdate redrawing the window's
  558.     contents as necessary. */
  559. void RWUpdate(WindowPtr rWin) {
  560.     RWindowHandle rwv;
  561.     Rect r;
  562.     short i;
  563.         /* set up locals */
  564.     rwv = (RWindowHandle) GetWRefCon(rWin);
  565.     
  566.         /* set up the drawing environment */
  567.     SetPort(rWin);
  568.     SetOrigin(0, 0);
  569.     ClipRect(&rWin->portRect);
  570.     BeginUpdate(rWin);
  571.         
  572.         /* draw the button controls and the fill area at the top of the window. */
  573.     SetRect(&r, 32*(3+(**rwv).nExtraButtons), 0, rWin->portRect.right, 32);
  574.     DrawFillBar(&r);
  575.     RedrawWindowButtons(rwv);
  576.     for (i=0; i<(**rwv).nExtraButtons; i++)
  577.         DrawCIconButton((**rwv).extraButtons[i], kCBup);
  578.         
  579.         /* draw a one pixel border at the bottom of that area */
  580.     MoveTo(0, 32);
  581.     LineTo(rWin->portRect.right-1, 32);
  582.  
  583.         /* if the window is not active, then gray out everything we
  584.         just drew.  */
  585.     if ( ! (**rwv).isActive) {
  586.         SetRect(&r, 0, 0, rWin->portRect.right, 33);
  587.         GrayOutBox(&r);
  588.     }
  589.         
  590.         /* draw the grow icon */
  591.     DrawGrowIconWithoutScrollLines(rWin);
  592.         
  593.         /* draw the HTML image.  we do this last as the time it takes
  594.         to complete may vary depending on the HTML content in the window.
  595.         This way, the window's structure and controls look solid and they
  596.         redraw in a consistent way. */
  597.     HRDraw((**rwv).renderer, rWin->visRgn);
  598.     
  599.         /* reset the drawing enviroment */
  600.     SetOrigin(0, 0);
  601.     EndUpdate(rWin);
  602. }
  603.  
  604.  
  605.  
  606. /* RWActivate should be called in response to activate events.*/
  607. void RWActivate(WindowPtr rWin, Boolean activate) {
  608.     RWindowHandle rwv;
  609.     Rect r;
  610.         /* set up locals */
  611.     rwv = (RWindowHandle) GetWRefCon(rWin);
  612.         /* set the active flag in the window's variables */
  613.     (**rwv).isActive = activate;
  614.         /* call the rendering library to activate or
  615.         deactivate the HTML object */
  616.     if (activate)
  617.         HRActivate((**rwv).renderer);
  618.     else HRDeactivate((**rwv).renderer);
  619.         /* post an update event so the grow icon
  620.         and the controls are re-drawn to reflect
  621.         the new active/inactive state. */
  622.     SetPort(rWin);
  623.     SetOrigin(0, 0);
  624.     SetRect(&r, 0, 0, rWin->portRect.right, 33);
  625.     InvalRect(&r);
  626.         /* ...and the grow box */
  627.     SetRect(&r, 0, 0, 16, 16);
  628.     OffsetRect(&r, rWin->portRect.right-16, rWin->portRect.bottom-16);
  629.     InvalRect(&r);
  630. }
  631.  
  632.  
  633. /* RWRecalculateSize should be called whenever the size of a rendering
  634.     window changes.  This routine resizes and redraws the windows
  635.     contents appropriately. */
  636. void RWRecalculateSize(WindowPtr rWin) {
  637.     RWindowHandle rwv;
  638.     Rect r;
  639.         /* set up locals */
  640.     rwv = (RWindowHandle) GetWRefCon(rWin);
  641.         /* set up the drawing environment */
  642.     SetPort(rWin);
  643.     SetOrigin(0, 0);
  644.         /* reset the html object's rendering area */
  645.     r = rWin->portRect;
  646.     SetRect(&r, r.left, r.top+33, r.right+1, r.bottom+1);
  647.     HRSetRenderingRect((**rwv).renderer, &r);
  648. }
  649.  
  650.  
  651. /* RWResetGotoMenu should be called before calling MenuKey or MenuSelect.  It
  652.     enables the back, forward, and home menu commands depending on what
  653.     commands are available and it rebuilds the history list at the bottom
  654.     of the go to menu. */
  655. void RWResetGotoMenu(WindowPtr rWin) {
  656.     RWindowHandle rwv;
  657.     MenuHandle goMenu;
  658.         /* set up locals */
  659.     rwv = (RWindowHandle) GetWRefCon(rWin);
  660.     goMenu = GetMenuHandle(mGo);
  661.         /* enable the back command */
  662.     if (CanGoBack((**rwv).history))
  663.         EnableItem(goMenu, iBack);
  664.     else DisableItem(goMenu, iBack);
  665.         /* enable the forward command */
  666.     if (CanGoForward((**rwv).history))
  667.         EnableItem(goMenu, iForward);
  668.     else DisableItem(goMenu, iForward);
  669.         /* enable the home command */
  670.     if (CanGoHome((**rwv).history))
  671.         EnableItem(goMenu, iHome);
  672.     else DisableItem(goMenu, iHome);
  673.         /* remove any items at the bottom of the menu */
  674.     while (CountMItems(goMenu) >= iGoSep)
  675.         DeleteMenuItem(goMenu, iGoSep);
  676.         /* append this window's history to the menu */
  677.     AppendHistoryToMenu((**rwv).history, goMenu);
  678. }
  679.  
  680.  
  681. /* RWHandleGotoMenu should be called when an item is chosen from the
  682.     go to menu.  item is the number of the item that was chosen. */
  683. void RWHandleGotoMenu(WindowPtr rWin, short item) {
  684.     RWindowHandle rwv;
  685.         /* set up locals */
  686.     rwv = (RWindowHandle) GetWRefCon(rWin);
  687.         /* err, this first part is pretty obvious...*/
  688.     if (item == iBack) {
  689.         GoBackCommand(rwv);
  690.     } else if (item == iForward) {
  691.         GoForwardCommand(rwv);
  692.     } else if (item == iHome) {
  693.         GoHomeCommand(rwv);
  694.     } else if (item > iGoSep) {
  695.         char** theURL;
  696.             /* if one of the history items is chosen from the bottom of
  697.             the menu, then we retrieve that item from the window's
  698.             history and call HRGoToURL to display it. */
  699.         if (GoToMenuItem((**rwv).history, (Handle*) &theURL, item - iGoSep) == noErr) {
  700.             MoveHHi((Handle) theURL);
  701.             HLock((Handle) theURL);
  702.             HRGoToURL((**rwv).renderer, *theURL, false, true);
  703.             SetPort(rWin);
  704.             RedrawWindowButtons(rwv);
  705.             DisposeHandle((Handle) theURL);
  706.         }
  707.     }
  708. }
  709.  
  710.  
  711. /* RWHandleMouseDown should be called in response to mouse down
  712.     events occuring inside of a rendering window.  This routine responds
  713.     to mouse clicks in the controls at the top of the window. */
  714. void RWHandleMouseDown(WindowPtr rWin, Point where) {
  715.     RWindowHandle rwv;
  716.         /* set up locals */
  717.     rwv = (RWindowHandle) GetWRefCon(rWin);
  718.     SetPort(rWin);
  719.     SetOrigin(0, 0);
  720.     ClipRect(&rWin->portRect);
  721.  
  722.         /* handle clicks in the standard buttons */
  723.     if (TrackCIconButton((**rwv).bback, where)) {
  724.         
  725.         GoBackCommand(rwv);
  726.         
  727.     } else if (TrackCIconButton((**rwv).bhome, where)) {
  728.     
  729.         GoHomeCommand(rwv);
  730.         
  731.     } else if (TrackCIconButton((**rwv).bforward, where)) {
  732.     
  733.         GoForwardCommand(rwv);
  734.         
  735.     } else {
  736.             /* if a user clicks in a custom button, then we
  737.             go to the link specified in it's data */
  738.         short i;
  739.         for (i=0; i<(**rwv).nExtraButtons; i++) {
  740.             if (TrackCIconButton((**rwv).extraButtons[i], where)) {
  741.                 OSStatus err;
  742.                 err = RWGoToButtonPage(rWin, (**rwv).extraButtons[i]);
  743.                 /* report errors here */
  744.                 DrawCIconButton((**rwv).extraButtons[i], kCBup);
  745.                 break;
  746.             }
  747.             
  748.         }
  749.     }
  750. }
  751.  
  752.  
  753. /* RWKeyDown should be called for keydown events when a rendering
  754.     window is the frontmost window.  This routine maps the left, up,
  755.     and right arrow keys to the back, home, and forward commands. */
  756. void RWKeyDown(WindowPtr rWin, char theKey) {
  757.     RWindowHandle rwv;
  758.     rwv = (RWindowHandle) GetWRefCon(rWin);
  759.     SetPort(rWin);
  760.     SetOrigin(0, 0);
  761.     ClipRect(&rWin->portRect);
  762.     switch (theKey) {
  763.         case kLeftArrowKey: /* left arrow key */
  764.             if (CanGoBack((**rwv).history)) {
  765.                 DrawCIconButton((**rwv).bback, kCBdown);
  766.                 GoBackCommand(rwv);
  767.             }
  768.             break;
  769.         case kUpArrowKey: /* up arrow key */
  770.             if (CanGoHome((**rwv).history)) {
  771.                 DrawCIconButton((**rwv).bhome, kCBdown);
  772.                 GoHomeCommand(rwv);
  773.             }
  774.             break;
  775.         case kDownArrowKey: /* right arrow key */
  776.             if (CanGoForward((**rwv).history)) {
  777.                 DrawCIconButton((**rwv).bforward, kCBdown);
  778.                 GoForwardCommand(rwv);
  779.             }
  780.             break;
  781.     }
  782. }
  783.  
  784.  
  785. /* RWOpen opens a new, empty rendering window.  If successful,
  786.     then *rWindow will contain a pointer to a newly created window. */
  787. OSStatus RWOpen(WindowPtr *rWindow) {
  788.     OSStatus err;
  789.     WindowPtr rwin;
  790.     short i, nExtraButtons;
  791.     HRReference rend; /* the window's rendering object */
  792.     HistoryDataHandle hist; /* the window's history */
  793.     RWindowHandle rwv; /* storage for the window's state variables */
  794.     RBCLRsrcHandle extraButtonIDs; /* extra button id list */
  795.     CIconButtonHandle backButton, homeButton, forwardButton;
  796.     CIconButtonHandle extraButtons[kExtraButtonsMax];
  797.         /* static globals */
  798.     static HRNewURLUPP gNewURLUPP = NULL;
  799.     static HRWasURLVisitedUPP gVisitedURLUPP = NULL;
  800.     static HRURLToFSSpecUPP gTranslateURLUPP = NULL;
  801.     static Point gPosition = { 0, 0};
  802.  
  803.         /* set up locals */
  804.     rwin = NULL;
  805.     rend = NULL;
  806.     hist = NULL;
  807.     rwv = NULL;
  808.     backButton = homeButton = forwardButton = NULL;
  809.     for (i=0; i<kExtraButtonsMax; i++) extraButtons[i] = NULL;
  810.     nExtraButtons = 0;
  811.     
  812.         /* get the buttons */
  813.     backButton = NewCIconButton(kBackDefaultButton);
  814.     if (backButton == NULL) { err = resNotFound; goto bail; }
  815.     homeButton = NewCIconButton(kHomeDefaultButton);
  816.     if (homeButton == NULL) { err = resNotFound; goto bail; }
  817.     forwardButton = NewCIconButton(kForwardDefaultButton);
  818.     if (forwardButton == NULL) { err = resNotFound; goto bail; }
  819.         /* get the extra buttons */
  820.     extraButtonIDs = (RBCLRsrcHandle) GetResource(kIconButtonIDListType, kExtraButtonsListID);
  821.     if (extraButtonIDs != NULL) {
  822.         nExtraButtons = (**extraButtonIDs).n;
  823.         if (nExtraButtons > kExtraButtonsMax) nExtraButtons = kExtraButtonsMax;
  824.         for (i=0; i < nExtraButtons; i++) {
  825.             extraButtons[i] = NewCIconButton((**extraButtonIDs).ids[i]);
  826.             if (extraButtons[i] == NULL) { err = resNotFound; goto bail; }
  827.             SetCIconButtonPosition(extraButtons[i], 32 * (3 + i), 0);
  828.         }
  829.     }
  830.  
  831.         /* allocate the window */
  832.     rwin = GetNewCWindow(kRenderingWindowID, NULL, (WindowPtr)(-1));
  833.     if (rwin == NULL) { err = resNotFound; goto bail; }
  834.     SetPort(rwin);
  835.         /* position it on the screen */
  836.     MoveWindow(rwin, gPosition.h + 20, gPosition.v + 50, true);
  837.     gPosition.h = (gPosition.h + 10) % 300;
  838.     gPosition.v = (gPosition.v + 32) % 200;
  839.         /* set up the renderer */
  840.     err = HRNewReference(&rend, kHRRendererHTML32Type, rwin);
  841.     if (err != noErr) goto bail;
  842.     err = HRSetGrowboxCutout(rend, true);
  843.     if (err != noErr) goto bail;
  844.         /* create the history */
  845.     hist = NewHistory();
  846.     if (hist == NULL) { err = memFullErr; goto bail; }
  847.         /* allocate the storage and store a handle to it in the refcon */
  848.     rwv = (RWindowHandle) NewHandleClear(offsetof(RWindowVars, extraButtons) + sizeof(CIconButtonHandle)*nExtraButtons);
  849.     if (rwv == NULL) { err = memFullErr; goto bail; }
  850.     (**rwv).rwindow = rwin;
  851.     (**rwv).renderer = rend;
  852.     (**rwv).history = hist;
  853.     (**rwv).isActive = false;
  854.     (**rwv).bback = backButton;
  855.     (**rwv).bhome = homeButton;
  856.     (**rwv).bforward = forwardButton;
  857.     (**rwv).nExtraButtons = nExtraButtons;
  858.     for (i=0; i<nExtraButtons; i++)
  859.         (**rwv).extraButtons[i] = extraButtons[i];
  860.     SetWRefCon(rwin, (long) rwv);
  861.         /* set up the new links call back */
  862.     if (gNewURLUPP == NULL) {
  863.         gNewURLUPP = NewHRNewURLUPP(MyNewURLProc);
  864.         if (gNewURLUPP == NULL) { err = memFullErr; goto bail; }
  865.     }
  866.     HRRegisterNewURLUPP( gNewURLUPP, rend, rwv);
  867.         /* set up the visited links call back */
  868.     if (gVisitedURLUPP == NULL) {
  869.         gVisitedURLUPP = NewHRWasURLVisitedUPP(MyHRWasURLVisitedProc);
  870.         if (gVisitedURLUPP == NULL) { err = memFullErr; goto bail; }
  871.     }
  872.     HRRegisterWasURLVisitedUPP( gVisitedURLUPP, rend, rwv);
  873.         /* set up the link translation call back */
  874.     if (gTranslateURLUPP == NULL) {
  875.         gTranslateURLUPP = NewHRURLToFSSpecUPP(MyHRURLToFSSpecProc);
  876.         if (gTranslateURLUPP == NULL) { err = memFullErr; goto bail; }
  877.     }
  878.     HRRegisterURLToFSSpecUPP( gTranslateURLUPP, rend, rwv);
  879.         /* add the window to the list of open windows */
  880.     if (gRWFirst == NULL) {
  881.         gRWFirst = gRWLast = rwv;
  882.     } else {
  883.         (**rwv).next = gRWFirst;
  884.         (**gRWFirst).prev = rwv;
  885.         gRWFirst = rwv;
  886.     }
  887.         /* recalculate the window's coordinates and show it */
  888.     RWRecalculateSize(rwin);
  889.     ShowWindow(rwin);
  890.     *rWindow = rwin;
  891.     return noErr;
  892.  
  893. bail:
  894.         /* if an error occurs, we recover and return the error code */
  895.     if (hist != NULL) DisposeHistory(hist);
  896.     if (rend != NULL) HRDisposeReference(rend);
  897.     if (rwin != NULL) DisposeWindow(rwin);
  898.     if (rwv != NULL) DisposeHandle((Handle) rwv);
  899.     if (backButton != NULL) DisposeCIconButton(backButton);
  900.     if (homeButton != NULL) DisposeCIconButton(homeButton);
  901.     if (forwardButton != NULL) DisposeCIconButton(forwardButton);
  902.     for (i=0; i < nExtraButtons; i++) {
  903.         if (extraButtons[i] != NULL) DisposeCIconButton(extraButtons[i]);
  904.     }
  905.     return err;
  906. }
  907.  
  908.  
  909. /* RWCloseWindow closes the rendering window pointed to by
  910.     rWin.  */
  911. void RWCloseWindow(WindowPtr rWin) {
  912.     RWindowHandle rwv;
  913.     short i;
  914.         /* set up locals */
  915.     rwv = (RWindowHandle) GetWRefCon(rWin);
  916.         /* delete the rendering object */
  917.     HRDisposeReference((**rwv).renderer);
  918.         /* delete the history */
  919.     DisposeHistory((**rwv).history);
  920.         /* deallocate the window */
  921.     DisposeWindow((**rwv).rwindow);
  922.         /* delete the icons */
  923.     DisposeCIconButton((**rwv).bback);
  924.     DisposeCIconButton((**rwv).bhome);
  925.     DisposeCIconButton((**rwv).bforward);
  926.     for (i=0; i < (**rwv).nExtraButtons; i++)
  927.         DisposeCIconButton((**rwv).extraButtons[i]);
  928.         /* remove from the rendering window list */
  929.     if ((**rwv).next != NULL)
  930.         (**(**rwv).next).prev = (**rwv).prev;
  931.     else gRWLast = (*rwv)->prev;
  932.     if ((**rwv).prev != NULL)
  933.         (**(**rwv).prev).next = (**rwv).next;
  934.     else gRWFirst = (**rwv).next;
  935.         /* delete storage */
  936.     DisposeHandle((Handle) rwv);
  937. }
  938.  
  939.  
  940. /* IsARenderingWindow returns true if rWin points to a rendering
  941.     window created by RWOpen. You should not call any of the routines
  942.     below for windows that are not rendering windows.  This routine
  943.     provides a convenient way to tell if a windowptr returned by one
  944.     of the toolbox routines is a rendering window. */
  945. Boolean IsARenderingWindow(WindowPtr rWin) {
  946.     RWindowHandle rover;
  947.         /* a null pointer cannot refer to a rendering window */
  948.     if (rWin == NULL) return false;
  949.         /* search the list of windows and see if it's there */
  950.     for (rover = gRWFirst; rover != NULL; rover = (**rover).next)
  951.         if (rWin == (**rover).rwindow)
  952.             return true;
  953.         /* if it's not there, return false. */    
  954.     return false;
  955. }
  956.